From 295cedb8b4fdf08e2011883426940776c9cac6b6 Mon Sep 17 00:00:00 2001 From: jhofstee Date: Wed, 9 Apr 2025 12:24:13 +0200 Subject: [PATCH] [PATCH] zlib: fix pointer alignment MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit The function AllocForBrotli prefixes the allocated memory with its size, and returns a pointer to the region after it. This pointer can however no longer be suitably aligned. Correct this by allocating the maximum of the the size of the size_t and the max alignment. On Arm 32bits the size_t is 4 bytes long, but the alignment is 8 for some NEON instructions. When Brotli is compiled with optimizations enabled newer GCC versions will use the NEON instructions and trigger a bus error killing node. see https://github.com/google/brotli/issues/1159 PR-URL: https://github.com/nodejs/node/pull/57727 Reviewed-By: Shelley Vohr Reviewed-By: Tobias Nießen Reviewed-By: Daniel Lemire Reviewed-By: Gerhard Stöbich Gbp-Pq: Topic sec Gbp-Pq: Name 10-zlib-fix-pointer-alignment.patch --- src/node_zlib.cc | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/node_zlib.cc b/src/node_zlib.cc index 66370e416..a537e7667 100644 --- a/src/node_zlib.cc +++ b/src/node_zlib.cc @@ -493,20 +493,22 @@ class CompressionStream : public AsyncWrap, public ThreadPoolWork { } static void* AllocForBrotli(void* data, size_t size) { - size += sizeof(size_t); + constexpr size_t offset = std::max(sizeof(size_t), alignof(max_align_t)); + size += offset; CompressionStream* ctx = static_cast(data); char* memory = UncheckedMalloc(size); if (UNLIKELY(memory == nullptr)) return nullptr; *reinterpret_cast(memory) = size; ctx->unreported_allocations_.fetch_add(size, std::memory_order_relaxed); - return memory + sizeof(size_t); + return memory + offset; } static void FreeForZlib(void* data, void* pointer) { if (UNLIKELY(pointer == nullptr)) return; CompressionStream* ctx = static_cast(data); - char* real_pointer = static_cast(pointer) - sizeof(size_t); + constexpr size_t offset = std::max(sizeof(size_t), alignof(max_align_t)); + char* real_pointer = static_cast(pointer) - offset; size_t real_size = *reinterpret_cast(real_pointer); ctx->unreported_allocations_.fetch_sub(real_size, std::memory_order_relaxed); -- 2.30.2